/*
 * Created on Feb 8, 2008
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package it.unibo.deis.lia.mmhc.rom;

import it.unibo.deis.lia.mmhc.util.*;

import java.net.*;
import java.util.Vector;
import java.io.*;

public class ClientRoutingManager extends Thread {

	private Channel channel;
	private RoutingManager rm;

	protected ClientRoutingManager(Channel channel, RoutingManager rm) {
		this.channel = channel;
		this.rm = rm;
	}

	public void run() {
		System.out.println("\tClientRoutingManager new channel: " + channel);
		try {
			boolean firstHop = channel.getConnector().isFixed();
			if (firstHop) {
				boolean activeChannel;
				rm.addAvailablePath(new Path(channel, 1, channel.getConnector()
						.getThroughputKBs(), 1, channel.getConnector()
						.getEnduranceEstimation()));
				do {
					activeChannel = false;
					Vector<Channel> availableChannels = rm
							.getAvailableChannels();
					for (int j = 0; j < availableChannels.size()
							&& activeChannel == false; j++) {
						Channel aChannel = availableChannels.elementAt(j);
						if (aChannel.getChannelLocalIPAddress().equals(
								channel.getChannelLocalIPAddress())) {
							activeChannel = true;
						}
					}
					Thread.sleep(2500);
				} while (activeChannel);
			} else {
				System.out
						.println("\tClientRoutingManager: channel.getChannelLocalIPAddress() "
								+ channel.getChannelLocalIPAddress());
				String octects[] = channel.getChannelLocalIPAddress().split(
						"[.]");
				String connectorIP = octects[0] + "." + octects[1] + "."
						+ octects[2] + "." + "1";
				System.out.println("\tClientRoutingManager: connectorIP "
						+ connectorIP);

				int attempts = 5;
				Socket s = null;
				do {
					System.out.println("\tClientRoutingManager: attempts "
							+ attempts);
					try {
						s = new Socket(connectorIP, 2400);
					} catch (Exception e) {
						sleep(1500);
						attempts--;
						if (attempts == 0)
							throw e;
					}
				} while (attempts > 0 && s == null);

				while (s != null) {
					// * 1) di tanto in tanto si connette al connector per
					// richiesta info sul path in uso;
					// * in questo modo il connector e' spronato a rivalutare il
					// path
					// * 2) inoltre controlla se il channel e' ancora attivo

					System.out
							.println("\tClientRoutingManager: connected to the connector! available attempts: "
									+ attempts);
					ObjectOutputStream oos = new ObjectOutputStream(s
							.getOutputStream());
					oos.flush();
					ObjectInputStream ois = new ObjectInputStream(s
							.getInputStream());
					oos.writeDouble(rm.localRequiredReliability);
					oos.flush();
					System.out
							.println("\tClientRoutingManager: sent requiredReliability "
									+ rm.localRequiredReliability);
					Path receivedPath = null;
					try {
						receivedPath = (Path) ois.readObject();
					} catch (EOFException e) {
						// TODO: handle exception
					}
					System.out
							.println("\tClientRoutingManager: received receivedPath "
									+ receivedPath);

					float throughput;
					System.out.println("\tClientRoutingManager receivedPath "
							+ receivedPath);
					System.out
							.println("\tClientRoutingManager receivedPath.getChannel() "
									+ receivedPath.getChannel());
					System.out.println("\tClientRoutingManager channel "
							+ channel);
					if (receivedPath.getThroughputKBs() < channel
							.getConnector().getThroughputKBs()) {
						throughput = receivedPath.getThroughputKBs();
					} else {
						throughput = channel.getConnector().getThroughputKBs();
					}
					throughput = (float) 0.7 * throughput
							/ receivedPath.getClients();

					Path bestPath = new Path(channel, receivedPath.getHops(),
							throughput, receivedPath.getClients(), receivedPath
									.getPathMobility()
									* channel.getConnector()
											.getEnduranceEstimation());
					System.out
							.println("\tClientRoutingManager: re-evaluated path  "
									+ bestPath);

					boolean newPath = true;
					Vector<Path> availablePaths = rm.getAvailablePaths();
					for (int j = 0; j < availablePaths.size()
							&& newPath == true; j++) {
						Path oldPath = availablePaths.elementAt(j);
						if (oldPath.getChannel().getChannelLocalIPAddress()
								.equals(
										bestPath.getChannel()
												.getChannelLocalIPAddress())) {
							newPath = false;
							rm.removeAvailablePath(oldPath);
							rm.addAvailablePath(bestPath);
							System.out
									.println("\tClientRoutingManager: (old path)  "
											+ bestPath);
						}
					}
					if (newPath) {
						System.out
								.println("\tClientRoutingManager: (new path)  "
										+ bestPath);
						rm.addAvailablePath(bestPath);
					}

					s.close();

					System.out.println("Currently available paths:");
					for (Path path : rm.getAvailablePaths()) {
						System.out.println(path);
					}

					sleep(5000);

					attempts = 5;
					s = null;
					do {
						System.out.println("\tClientRoutingManager: attempts "
								+ attempts);
						try {
							s = new Socket(connectorIP, 2400);
						} catch (Exception e) {
							sleep(1500);
							attempts--;
							if (attempts == 0)
								throw e;
						}
					} while (attempts > 0 && s == null);
				}
				// Non riesco piu` a connettermi al ServerRoutingManager.
				// considero il channel non piu` valido
				System.out.println("\tClientRoutingManager: closing Channel"
						+ channel);
				rm.removeAvailableChannel(channel);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// elimina il corrispondente Path, se esiste
		Vector<Path> availablePaths = rm.getAvailablePaths();
		boolean found = true;
		for (int j = 0; j < availablePaths.size() && found == false; j++) {
			Path oldPath = availablePaths.elementAt(j);
			if (oldPath.getChannel().getChannelLocalIPAddress().equals(
					channel.getChannelLocalIPAddress())) {
				found = true;
				rm.removeAvailablePath(oldPath);
				System.out.println("\tClientRoutingManager end channel: "
						+ channel);
			}
		}
	}
}
